package org.shenba.springbible.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLGrabber {

	private static final Document xmlDocument = getXMLDocument();
	private static final String filePath = "kjv.xml";

	/**
	 * @return
	 */
	public static Document getXMLDocument() {
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();
		builderFactory.setIgnoringElementContentWhitespace(false);
		Document document = null;
		try {
			DocumentBuilder builder = builderFactory.newDocumentBuilder();
			document = builder.parse(XMLGrabber.class.getResourceAsStream(filePath));
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return document;
	}

	/**
	 * @param nodes
	 *            - List of nodes (NodeList)
	 * @param attribute
	 *            - Name of the attribute
	 * @param value
	 *            - value of the attribute
	 * @return First node with matching attribute value. Case sensitive, string
	 *         comparison is done
	 */
	public static Node findNodeByAttribute(NodeList nodes, String attribute,
			String value) {
		Node matchingNode = null;
		if (nodes == null || attribute == null || value == null) {
			return null;
		}
		int nodeCount = nodes.getLength();
		for (int i = 0; i < nodeCount; i++) {
			matchingNode = nodes.item(i);
			if (matchingNode.getNodeName().equals("#text")) {
				continue;
			}
			if (matchingNode.getAttributes().getNamedItem(attribute)
					.getNodeValue().equals(value)) {
				return matchingNode;
			}
		}
		return matchingNode;
	}

	/**
	 * @return Will return null is the document is null. Else returns an
	 *         ArrayList of Book titles in the document. Will return an empty
	 *         ArrayList if the document is empty.
	 */
	public static ArrayList<String> getListOfBooks() {
		ArrayList<String> listOfBooks = new ArrayList<String>();
		NodeList books = xmlDocument.getElementsByTagName("book");
		for (int i = 0; i < books.getLength(); i++) {
			listOfBooks.add(books.item(i).getAttributes().getNamedItem("name")
					.getNodeValue());
		}
		return listOfBooks;
	}

	/**
	 * @param parent
	 *            - parent node
	 * @return Returns non empty text nodes' count
	 */
	private static int getRealChildCount(Node parent) {
		int childCount = 0;
		if (parent == null) {
			return childCount;
		}
		NodeList children = parent.getChildNodes();
		int allChildren = children.getLength();
		for (int i = 0; i < allChildren; i++) {
			if (children.item(i).getNodeName().equals("#text")) {
				continue;
			}
			childCount++;
		}
		return childCount;
	}
	
	public static int getChapters(String book) {
		NodeList books = xmlDocument.getElementsByTagName("book");
        Node bookNode = findNodeByAttribute(books, "name", book);
        return getRealChildCount(bookNode);
	}
	
	public static int getVerses(String book, String chapter) {
		NodeList books = xmlDocument.getElementsByTagName("book");
        Node bookNode = findNodeByAttribute(books, "name", book);
        Node chapterNode = findNodeByAttribute(bookNode.getChildNodes(), "name", chapter);
        return getRealChildCount(chapterNode);
	}
	
	public static String getVerse(String book, String chapter, String verse) {
		NodeList books = xmlDocument.getElementsByTagName("book");
        Node bookNode = findNodeByAttribute(books, "name", book);
        Node chapterNode = findNodeByAttribute(bookNode.getChildNodes(), "name", chapter);
        Node verseNode = findNodeByAttribute(chapterNode.getChildNodes(), "name", verse);
        return verseNode.getTextContent();
	}
}
